﻿/*
** Haaf's Game Engine 1.5
** Copyright (C) 2003-2004, Relish Games
** hge.relishgames.com
**
** hgeSprite helper class implementation
*/
module		core.hgesprite;


private	import		core.hgeall;
private	import		std.c.math;



extern (C) void *memcpy(void *, void *, uint);

class hgeSprite
{
public:

	void		SetBlendMode(int blend) { quad.blend=blend; }
	void		SetHotSpot(float x, float y) { hotX=x; hotY=y; }

	HTEXTURE	GetTexture()  		{ return quad.tex; }
	void		GetTextureRect(float *x, float *y, float *w, float *h)  { *x=tx; *y=ty; *w=width; *h=height; }
	uint		GetColor(int i=0)  	{ return quad.v[i].col; }
	float		GetZ(int i=0)  		{ return quad.v[i].z; }
	int			GetBlendMode()  		{ return quad.blend; }
	void		GetHotSpot(float *x, float *y)  { *x=hotX; *y=hotY; }
	void		GetFlip(bool *bX, bool *bY)  { *bX=bXFlip; *bY=bYFlip; }

	hgeRect*	GetBoundingBox(float x, float y, hgeRect *rect)  { rect.Set(x-hotX, y-hotY, x-hotX+width, y-hotY+height); return rect; }

	float		GetWidth()  			{ return width; }
	float		GetHeight()  			{ return height; }



	this(HTEXTURE texture, float texx, float texy, float w, float h)
	{
		this();			// 调用私有构造函数
		
		float texx1, texy1, texx2, texy2;
		
		tx=texx; ty=texy;
		width=w; height=h;

		if(texture)
		{
			tex_width = cast(float)hge.Texture_GetWidth(texture);
			tex_height = cast(float)hge.Texture_GetHeight(texture);
		}
		else
		{
			tex_width = 1.0f;
			tex_height = 1.0f;
		}

		hotX=0; hotY=0;
		bXFlip=false; bYFlip=false;
		quad.tex=texture;

		texx1=texx/tex_width;
		texy1=texy/tex_height;
		texx2=(texx+w)/tex_width;
		texy2=(texy+h)/tex_height;

		quad.v[0].tx = texx1; quad.v[0].ty = texy1;
		quad.v[1].tx = texx2; quad.v[1].ty = texy1;
		quad.v[2].tx = texx2; quad.v[2].ty = texy2;
		quad.v[3].tx = texx1; quad.v[3].ty = texy2;

		quad.v[0].z = 
		quad.v[1].z = 
		quad.v[2].z = 
		quad.v[3].z = 0.5f;
		
		quad.v[0].col = 
		quad.v[1].col = 
		quad.v[2].col = 
		quad.v[3].col = 0xffffffff;

		quad.blend=BLEND_DEFAULT;

	}

	this( hgeSprite spr)
	{
		this();		// 调用私有构造函数
		mParent						=spr.mParent;
		mChildren 					=spr.mChildren;
		//static hgeSprite[hgeSprite] 	=spr.sprites;	  // 静态函数不须拷贝
		//static ifHge 		=spr.hge;
		quad	=spr.quad;
		tx		=spr.tx;
		ty		=spr.ty;
		width	=spr.width; 
		height	=spr.height;
		tex_width		=spr.tex_width;
		tex_height		=spr.tex_height;
		hotX			=spr.hotX;
		hotY			=spr.hotY;
		bXFlip			=spr.bXFlip;
		bYFlip			=spr.bYFlip;
	}

	~this()
	{ 
		mes("		-->> 销毁精灵实例,   总数== " , sprites.length );
		sprites.remove(this);
	}

	void Render(float x, float y)
	{
		float tempx1, tempy1, tempx2, tempy2;

		tempx1 = x-hotX;
		tempy1 = y-hotY;
		tempx2 = x+width-hotX;
		tempy2 = y+height-hotY;

		quad.v[0].x = tempx1; quad.v[0].y = tempy1;
		quad.v[1].x = tempx2; quad.v[1].y = tempy1;
		quad.v[2].x = tempx2; quad.v[2].y = tempy2;
		quad.v[3].x = tempx1; quad.v[3].y = tempy2;

		hge.Gfx_RenderQuad(&quad);
	}


	void RenderEx(float x, float y, float rot, float hscale=1.0f, float vscale=0.0f)
	{
		float tx1, ty1, tx2, ty2;
		float sint, cost;

		if(vscale==0) vscale=hscale;

		tx1 = -hotX*hscale;
		ty1 = -hotY*vscale;
		tx2 = (width-hotX)*hscale;
		ty2 = (height-hotY)*vscale;

		if (rot != 0.0f)
		{
			cost = cosf(rot);
			sint = sinf(rot);
				
			quad.v[0].x  = tx1*cost - ty1*sint + x;
			quad.v[0].y  = tx1*sint + ty1*cost + y;	

			quad.v[1].x  = tx2*cost - ty1*sint + x;
			quad.v[1].y  = tx2*sint + ty1*cost + y;	

			quad.v[2].x  = tx2*cost - ty2*sint + x;
			quad.v[2].y  = tx2*sint + ty2*cost + y;	

			quad.v[3].x  = tx1*cost - ty2*sint + x;
			quad.v[3].y  = tx1*sint + ty2*cost + y;	
		}
		else
		{
			quad.v[0].x = tx1 + x; quad.v[0].y = ty1 + y;
			quad.v[1].x = tx2 + x; quad.v[1].y = ty1 + y;
			quad.v[2].x = tx2 + x; quad.v[2].y = ty2 + y;
			quad.v[3].x = tx1 + x; quad.v[3].y = ty2 + y;
		}

		hge.Gfx_RenderQuad(&quad);
	}


	void RenderStretch(float x1, float y1, float x2, float y2)
	{
		quad.v[0].x = x1; quad.v[0].y = y1;
		quad.v[1].x = x2; quad.v[1].y = y1;
		quad.v[2].x = x2; quad.v[2].y = y2;
		quad.v[3].x = x1; quad.v[3].y = y2;

		hge.Gfx_RenderQuad(&quad);
	}


	void Render4V(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)
	{
		quad.v[0].x = x0; quad.v[0].y = y0;
		quad.v[1].x = x1; quad.v[1].y = y1;
		quad.v[2].x = x2; quad.v[2].y = y2;
		quad.v[3].x = x3; quad.v[3].y = y3;

		hge.Gfx_RenderQuad(&quad);
	}


	hgeRect* GetBoundingBoxEx(float x, float y, float rot, float hscale, float vscale, hgeRect *rect) 
	{
		float tx1, ty1, tx2, ty2;
		float sint, cost;

		rect.Clear();
		
		tx1 = -hotX*hscale;
		ty1 = -hotY*vscale;
		tx2 = (width-hotX)*hscale;
		ty2 = (height-hotY)*vscale;

		if (rot != 0.0f)
		{
			cost = cosf(rot);
			sint = sinf(rot);
				
			rect.Encapsulate(tx1*cost - ty1*sint + x, tx1*sint + ty1*cost + y);	
			rect.Encapsulate(tx2*cost - ty1*sint + x, tx2*sint + ty1*cost + y);	
			rect.Encapsulate(tx2*cost - ty2*sint + x, tx2*sint + ty2*cost + y);	
			rect.Encapsulate(tx1*cost - ty2*sint + x, tx1*sint + ty2*cost + y);	
		}
		else
		{
			rect.Encapsulate(tx1 + x, ty1 + y);
			rect.Encapsulate(tx2 + x, ty1 + y);
			rect.Encapsulate(tx2 + x, ty2 + y);
			rect.Encapsulate(tx1 + x, ty2 + y);
		}

		return rect;
	}

	void SetFlip(bool bX, bool bY)
	{
		float tx, ty;

		if(bX != bXFlip)
		{
			tx=quad.v[0].tx; quad.v[0].tx=quad.v[1].tx; quad.v[1].tx=tx;
			ty=quad.v[0].ty; quad.v[0].ty=quad.v[1].ty; quad.v[1].ty=ty;
			tx=quad.v[3].tx; quad.v[3].tx=quad.v[2].tx; quad.v[2].tx=tx;
			ty=quad.v[3].ty; quad.v[3].ty=quad.v[2].ty; quad.v[2].ty=ty;
			bXFlip=!bXFlip;
		}

		if(bY != bYFlip)
		{
			tx=quad.v[0].tx; quad.v[0].tx=quad.v[3].tx; quad.v[3].tx=tx;
			ty=quad.v[0].ty; quad.v[0].ty=quad.v[3].ty; quad.v[3].ty=ty;
			tx=quad.v[1].tx; quad.v[1].tx=quad.v[2].tx; quad.v[2].tx=tx;
			ty=quad.v[1].ty; quad.v[1].ty=quad.v[2].ty; quad.v[2].ty=ty;
			bYFlip=!bYFlip;
		}
	}


	void SetTexture(HTEXTURE tex)
	{
		float tx1,ty1,tx2,ty2;
		float tw,th;

		quad.tex=tex;

		if(tex)
		{
			tw = cast(float)hge.Texture_GetWidth(tex);
			th = cast(float)hge.Texture_GetHeight(tex);
		}
		else
		{
			tw = 1.0f;
			th = 1.0f;
		}

		if(tw!=tex_width || th!=tex_height)
		{
			tx1=quad.v[0].tx*tex_width;
			ty1=quad.v[0].ty*tex_height;
			tx2=quad.v[2].tx*tex_width;
			ty2=quad.v[2].ty*tex_height;

			tex_width=tw;
			tex_height=th;

			tx1/=tw; ty1/=th;
			tx2/=tw; ty2/=th;

			quad.v[0].tx=tx1; quad.v[0].ty=ty1; 
			quad.v[1].tx=tx2; quad.v[1].ty=ty1; 
			quad.v[2].tx=tx2; quad.v[2].ty=ty2; 
			quad.v[3].tx=tx1; quad.v[3].ty=ty2; 
		}
	}


	void SetTextureRect(float x, float y, float w, float h)
	{
		float tx1, ty1, tx2, ty2;
		bool bX,bY;

		tx=x; ty=y; width=w; height=h;

		tx1=tx/tex_width; ty1=ty/tex_height;
		tx2=(tx+w)/tex_width; ty2=(ty+h)/tex_height;

		quad.v[0].tx=tx1; quad.v[0].ty=ty1; 
		quad.v[1].tx=tx2; quad.v[1].ty=ty1; 
		quad.v[2].tx=tx2; quad.v[2].ty=ty2; 
		quad.v[3].tx=tx1; quad.v[3].ty=ty2; 

		bX=bXFlip; bY=bYFlip;
		bXFlip=false; bYFlip=false;
		SetFlip(bX,bY);

	/////////////////// consider animation frame somehow! ////////////////
	}


	void SetColor(uint col, int i=-1)
	{
		if(i!=-1) quad.v[i].col=col;
		else { quad.v[0].col=quad.v[1].col=quad.v[2].col=quad.v[3].col=col; }
	}

	void SetZ(float z, int i=-1)
	{
		if(i!=-1) quad.v[i].z=z;
		else { quad.v[0].z=quad.v[1].z=quad.v[2].z=quad.v[3].z=z; }
	}
	
	// 设置 位置
	void 	setPos(float ax, float ay)	{	mPosX=ax;	mPosY=ay;	}
	void 	posx(float ax)	{ 	mPosX = ax;	}
	void 	posy(float ay)	{	mPosY = ay;	}
	float	posx()			{ return mPosX;}
	float	posy()			{ return mPosY;}

	// 设置 旋转
	void 	rot(float ar)	{	mRot = ar;	}
	float	rot()			{ return mRot;}
	// 设置	缩放
	void 	sclW(float _w)	{	mSclW = _w;	}
	float	sclH()			{ return mSclH;}
	
	
	
	static void renderAll()		// 渲染所有精灵
	{
		hgeSprite[] rendersprites;
		
		foreach(hgeSprite s; sprites)	//刷新所有精灵对象
		{
			if(s.update)
				s.update();
				
			if(s.mVisible != 0)
				rendersprites ~= s;		// 去除 不可见属性的精灵
		}


		rendersprites.sort;			// 排序

		// render
		foreach(hgeSprite s; rendersprites)
		{
			if(s.draw) 
				s.draw();
			else
				s.RenderEx(s.mPosX, s.mPosY, s.mRot, s.mSclW, s.mSclH);
		}
	}






//////////////////////////////////  保护属性	////////////////////////

protected:

	this()								// 私有构造函数
	{
		if(!hge)hge = gameInfo.hge();

		sprites[this] = this;
		mes("		-->> 创建精灵实例,   总数== " , sprites.length );
	}
	

	void addChild(hgeSprite c)				// 加入精灵
	{
		if(c in mChildren)
			throw new hgeException("Sprite.addChild() - Child already exists in sprite!");
		mChildren[c] = c;
	}

	void removeChild(hgeSprite c)			// 删除精灵
	{
		if(!(c in mChildren))
			throw new hgeException("Sprite.removeChild() - Child does not exist in sprite!");
		mChildren.remove(c);
	}
	
	
	
	float 	mPosX=0,	mPosY=0;
	float	mGPosX=0,	mGPosY=0;

	float 	mRot = 0;
	float 	mGRot = 0;
	float	mSclW=1.0f,	mSclH=0;
	
	float	mSizeX=0,	mSizeY=0;
//	D3DXVECTOR3 mOffset;

	bool mVisible = true;
	bool mMatNeedsUpdate;
	
	hgeSprite 						mParent;		//父节点
	hgeSprite[hgeSprite] 			mChildren;		//子节点 数组
	static hgeSprite[hgeSprite] 	sprites;		//精灵	 数组
	
typedef  void function( ) 		updateFunc;
	updateFunc			update	=null;			//刷新函数  
	updateFunc			draw	=null;			//绘制函数 	
	static ifHge 		hge;

	hgeQuad		quad;
	float		tx, ty, width, height;
	float		tex_width, tex_height;
	float		hotX, hotY;
	bool		bXFlip, bYFlip;
};